-
Notifications
You must be signed in to change notification settings - Fork 429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent Unnecessary Update Request in Facilities Section #8956
base: develop
Are you sure you want to change the base?
Prevent Unnecessary Update Request in Facilities Section #8956
Conversation
✅ Deploy Preview for care-ohc ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
There's already another PR for the infinite load issues for Beds. In the future, make sure to get issue assigned or mention in the original thread before starting to work on an issue. |
I had made those necessary changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add package-lock back in (checked out from develop branch).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
src/components/Form/Form.tsx
Outdated
@@ -23,6 +23,7 @@ type Props<T extends FormDetails> = { | |||
onDraftRestore?: (newState: FormState<T>) => void; | |||
children: (props: FormContextValue<T>) => React.ReactNode; | |||
hideRestoreDraft?: boolean; | |||
showSaveAndAddMoreBtn?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the prefix show
makes it read as expected type to be a boolean, but string is expected. This could be confusing.
How about a more generic solution that'd allow us to freely add any type of button and make the actual component that uses this component define what type of button to show specifically?
showSaveAndAddMoreBtn?: string; | |
additionalButtons?: { type: "submit" | "button"; label: string; id: string }[]; |
src/components/Form/Form.tsx
Outdated
@@ -14,7 +14,7 @@ type Props<T extends FormDetails> = { | |||
defaults: T; | |||
asyncGetDefaults?: (() => Promise<T>) | false; | |||
validate?: (form: T) => FormErrors<T>; | |||
onSubmit: (form: T) => Promise<FormErrors<T> | void>; | |||
onSubmit: (form: T, btnType?: string) => Promise<FormErrors<T> | void>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onSubmit: (form: T, btnType?: string) => Promise<FormErrors<T> | void>; | |
onSubmit: (form: T, source?: string) => Promise<FormErrors<T> | void>; |
src/components/Form/Form.tsx
Outdated
@@ -34,6 +35,8 @@ const Form = <T extends FormDetails>({ | |||
const [isLoading, setIsLoading] = useState(!!asyncGetDefaults); | |||
const [state, dispatch] = useAutoSaveReducer<T>(formReducer, initial); | |||
|
|||
const [isDirty, setIsDirty] = useState(false); // Added isDirty state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove obvious comments
const [isDirty, setIsDirty] = useState(false); // Added isDirty state | |
const [isDirty, setIsDirty] = useState(false); |
if (valid) { | ||
setIsLoading(true); | ||
//Converting new data from string to Number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//Converting new data from string to Number |
Fix : Unnecessary Update Requests in Shifting and Resource Records #8982 |
👋 Hi, @kihan2518B, This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there. |
@rithviknishad can you review my changes? |
src/components/Form/Form.tsx
Outdated
onSubmit: ( | ||
form: T, | ||
source?: string, | ||
discharged?: boolean, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
passing "discharged" in a generic reusable component is not ideal.
discharged?: boolean, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I Thought it is necessary to keep it in Form component to use it in ShitDetailsUpdate Component
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't see any usages that is passing the third argument to this function when invoking. Can you point it out if present?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will remove it
name="status" | ||
value={field("status").value} | ||
options={resourceStatusOptions} | ||
onChange={(e: any) => field("status").onChange(e)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any
type not allowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'ill remove it
<UserAutocomplete | ||
label="Assigned To" | ||
value={field("assigned_to_object").value} | ||
onChange={(e: any) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove any
type here too and all other places that you've added/modified
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
src/components/Form/Form.tsx
Outdated
if (btn.label) { | ||
return ( | ||
<Submit | ||
id={btn.id} | ||
type={btn.type} | ||
disabled={disabled || !isDirty} | ||
label={btn.label} | ||
/> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- why have an if block checking if label is present? the type definition says it's not nullable.
- forgot to pass
key
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did removed it.
I think it would give an additional check
WalkthroughThe changes involve significant updates to several components related to form handling within the application. The Changes
Assessment against linked issues
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Outside diff range and nitpick comments (12)
src/components/Facility/FacilityBedCapacity.tsx (3)
Line range hint
14-14
: Consider adding proper TypeScript types for props.Using
any
type for props reduces type safety and makes the code more prone to runtime errors.Consider defining a proper interface:
interface FacilityBedCapacityProps { facilityId: string; } export const FacilityBedCapacity = (props: FacilityBedCapacityProps) => {
Line range hint
19-24
: Add loading and error states for capacityQuery.The component doesn't handle loading or error states for the capacity query, which could lead to poor user experience.
Consider adding loading and error handling:
if (capacityQuery.isLoading) { return <LoadingSpinner />; } if (capacityQuery.error) { return <ErrorMessage error={capacityQuery.error} />; }
Line range hint
93-103
: Consider adding a tooltip for disabled state.When the button is disabled, users should understand why they can't add more bed types.
Add a tooltip to improve user experience:
<ButtonV2 id="facility-add-bedtype" className="w-full md:w-auto" onClick={() => setBedCapacityModalOpen(true)} disabled={BED_TYPES.length === capacityQuery.data?.count} authorizeFor={NonReadOnlyUsers} + title={BED_TYPES.length === capacityQuery.data?.count ? "All bed types have been added" : ""} >
src/components/Form/Form.tsx (2)
17-17
: Consider usingundefined
instead ofvoid
in the union type.The static analysis tool correctly flags that
void
in a union type can be confusing. Usingundefined
would be more appropriate here as it better represents the absence of a return value.- onSubmit: (form: T, source?: string) => Promise<FormErrors<T> | void>; + onSubmit: (form: T, source?: string) => Promise<FormErrors<T> | undefined>;🧰 Tools
🪛 Biome
[error] 17-17: void is confusing inside a union type.
Unsafe fix: Use undefined instead.
(lint/suspicious/noConfusingVoidType)
80-96
: Consider simplifying and improving the value comparison logic.While the current implementation works, it could be made more robust and maintainable.
- if (typeof props.defaults[name] == typeof value) { - setIsDirty(props.defaults[name] !== value); - } else { - setIsDirty(JSON.stringify(props.defaults[name]) !== value); - } + const defaultValue = props.defaults[name]; + const isChanged = typeof value === 'object' && value !== null + ? JSON.stringify(defaultValue) !== JSON.stringify(value) + : defaultValue !== value; + setIsDirty(isChanged);src/components/Facility/StaffCapacity.tsx (1)
34-42
: Consider adding proper TypeScript types.While the reducer implementation is good, it would benefit from proper TypeScript types instead of using
any
.-const doctorCapacityReducer = (state = initialState, action: any) => { +type DoctorCapacityAction = + | { type: 'set_form'; form: typeof initForm } + | { type: 'set_error'; errors: typeof initForm } + | { type: 'set_field'; name: string; value: string; error?: string }; + +const doctorCapacityReducer = ( + state = initialState, + action: DoctorCapacityAction +) => {src/components/Facility/BedCapacity.tsx (2)
260-260
: Enhance internationalization by translating the 'Bed Type' labelIn the
SelectFormField
component, the label is set to"Bed Type"
. Consider using thet
function to translate this label for internationalization support.Apply this diff to use the translation function:
- label="Bed Type" + label={t("bed_type")}
264-289
: Ensure all form labels are translated for consistencyThe labels for form fields such as "Total Capacity" and "Currently Occupied" are hardcoded. To maintain consistency and support multiple languages, consider using the
t
function for these labels.Update the labels as follows:
- label="Total Capacity" + label={t("total_capacity")} ... - label="Currently Occupied" + label={t("currently_occupied")}src/components/Resource/ResourceDetailsUpdate.tsx (2)
Line range hint
35-36
: Add missing required fields to validationThe
title
andreason
fields are essential for the resource request but are not included in therequiredFields
object. As a result, they are not validated for emptiness, which may allow submission of incomplete forms.Consider adding
title
andreason
to therequiredFields
to ensure they are validated properly:const requiredFields: any = { approving_facility_object: { errorText: "Resource approving facility can not be empty.", }, + title: { + errorText: "Request title cannot be empty.", + }, + reason: { + errorText: "Description of request cannot be empty.", + }, assigned_facility_type: { errorText: "Please Select Facility Type", }, };
85-85
: Check for unnecessary state managementThe
assignedUserLoading
state is obtained fromuseQuery
, but there is also anisLoading
state managed separately. Ensure that loading states are handled consistently to avoid confusion or redundant renders.Consider consolidating loading states or clearly distinguishing their purposes.
src/components/Shifting/ShiftDetailsUpdate.tsx (2)
174-177
: Unused parametersource
inhandleSubmit
functionThe
source
parameter in thehandleSubmit
function is not used within the function body. Consider removing it to clean up the code.Apply this diff to remove the unused parameter:
const handleSubmit = async ( form: typeof initForm, - source?: string, discharged = false, ) => {
344-366
: SimplifysetSelected
function inFacilitySelect
The
setSelected
function can be simplified by directly updating theshifting_approving_facility_object
without the redundantapproving_facility
field, which may not be necessary.Apply this diff to simplify the function:
setSelected={(obj: any) => { field("shifting_approving_facility_object").onChange({ name: "shifting_approving_facility_object", value: obj, }); - field("approving_facility").onChange({ - name: "approving_facility", - value: obj.id, - }); }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (6)
src/components/Facility/BedCapacity.tsx
(5 hunks)src/components/Facility/FacilityBedCapacity.tsx
(1 hunks)src/components/Facility/StaffCapacity.tsx
(3 hunks)src/components/Form/Form.tsx
(8 hunks)src/components/Resource/ResourceDetailsUpdate.tsx
(5 hunks)src/components/Shifting/ShiftDetailsUpdate.tsx
(4 hunks)
🧰 Additional context used
🪛 Biome
src/components/Form/Form.tsx
[error] 17-17: void is confusing inside a union type.
Unsafe fix: Use undefined instead.
(lint/suspicious/noConfusingVoidType)
🔇 Additional comments (12)
src/components/Facility/FacilityBedCapacity.tsx (1)
95-95
:
Verify the disabled condition logic.
The disabled condition BED_TYPES.length === capacityQuery.data?.count
might not accurately reflect the actual bed types in use. Consider using the results array length instead.
Apply this diff to fix the condition:
-disabled={BED_TYPES.length === capacityQuery.data?.count}
+disabled={BED_TYPES.length === capacityQuery.data?.results.length}
Let's verify the current implementation:
src/components/Form/Form.tsx (5)
26-30
: LGTM! Well-typed additional buttons implementation.
The additionalButtons type definition is clear and type-safe, providing good flexibility for custom button configurations.
42-42
: LGTM! Good implementation of form dirty state tracking.
The isDirty state effectively addresses the PR objective of preventing unnecessary update requests by tracking form modifications.
56-56
: LGTM! Clean implementation of button source tracking and state reset.
The submit handler effectively:
- Captures the source button ID in a type-safe manner
- Resets the dirty state appropriately after submission
Also applies to: 70-72
115-115
: LGTM! Appropriate reset of dirty state on draft restoration.
The isDirty state is correctly reset when a draft is restored, maintaining form state consistency.
142-158
: LGTM! Well-implemented button rendering with consistent state management.
The button implementation:
- Maintains consistent disabled state across all buttons
- Properly identifies buttons with unique IDs
- Cleanly renders additional buttons when provided
src/components/Facility/StaffCapacity.tsx (3)
5-7
: LGTM! Good architectural improvement.
The integration of the Form component and related utilities provides better form state management and helps prevent unnecessary updates.
84-98
: LGTM! Validation improvements implemented as requested.
The validation logic has been improved as per previous review feedback, with better readability using validForm
.
146-197
: Verify the "Save & Add More" functionality implementation.
The implementation looks good and follows the previous review feedback about keeping two buttons. Let's verify if this component is used consistently across the codebase.
✅ Verification successful
"Save & Add More" functionality is consistently implemented
The search results show that the "save-and-add-more" functionality is consistently implemented in both StaffCapacity.tsx
and BedCapacity.tsx
components, following the same pattern:
- Both components handle the "save-and-add-more" source in their close handlers
- Both use identical structure for the additionalButtons prop with the same button ID and type
- The implementation in the review matches the pattern used elsewhere in the codebase
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for consistent Form component usage with additionalButtons
# across the codebase
# Search for Form components with additionalButtons prop
rg -A 5 "additionalButtons=\[" --type typescript --type tsx
# Search for similar save-and-add-more patterns
ast-grep --pattern 'additionalButtons={[
{
id: "save-and-add-more",
$$$
}
]}'
Length of output: 188
Script:
#!/bin/bash
# Let's try a different approach to search for Form components with additional buttons
# Search for Form components with additionalButtons
rg -U "additionalButtons=\{.*\}" --type=tsx -A 5
# Also search for save-and-add-more pattern with more flexible matching
rg -U "save-and-add-more" --type=tsx -A 5
# Search for Form components to check overall usage pattern
rg "<Form\s+" --type=tsx -A 5
Length of output: 208
Script:
#!/bin/bash
# Let's try without specifying file types and use more general patterns
# Search for Form components with additionalButtons
rg -U "additionalButtons=\{.*\}"
# Search for save-and-add-more pattern
rg -U "save-and-add-more" -A 5
# Search for Form components usage
rg "<Form\s+" -A 5
Length of output: 2453
src/components/Facility/BedCapacity.tsx (1)
232-247
: Conditional rendering of 'Save & Add More' button implemented correctly
The addition of the additionalButtons
prop to the Form
component and the conditional rendering of the "Save & Add More" button align with the previous suggestions and enhance the user experience.
src/components/Shifting/ShiftDetailsUpdate.tsx (2)
492-502
: Handle missing breathlessness_level
errors
Since breathlessness_level
is required when wartimeShifting
is enabled, ensure that error messages are displayed correctly when the field is not filled.
Run the following script to verify error handling:
#!/bin/bash
# Description: Check where 'breathlessness_level' errors are handled.
# Test: Search for usage of 'breathlessness_level' in error handling.
rg 'errors\[.*breathlessness_level.*\]'
452-462
: Ensure patient_category
has a default value
The patient_category
field is required but may not have a default value in initForm
, which could lead to form validation errors.
You can check if patient_category
is set properly in initForm
:
Number(state.form[field] < 0) | ||
) { | ||
validForm = false; | ||
} else if (field === "currentOccupancy" && Number(form[field] < 0)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix logical error in number conversion within conditional checks
There is a logical error in the way Number()
is used within the conditional statements. The expression Number(form[field] < 0)
converts the boolean result of form[field] < 0
into a number (0
or 1
), which is not the intended comparison.
To fix this issue, you should convert form[field]
to a number before performing the comparison.
Apply this diff to correct the conditionals:
- } else if (field === "currentOccupancy" && Number(form[field] < 0)) {
+ } else if (field === "currentOccupancy" && Number(form[field]) < 0) {
...
- } else if (field === "totalCapacity" && Number(form[field] < 0)) {
+ } else if (field === "totalCapacity" && Number(form[field]) < 0) {
Also applies to: 126-126
value: obj, | ||
}); | ||
field("assigned_facility").onChange({ | ||
name: "assigned_facility", | ||
value: obj.id, | ||
}); | ||
}} | ||
errors={state.errors.assigned_facility} | ||
/> | ||
</div> | ||
<div> | ||
<TextFormField | ||
label="Required Quantity" | ||
name="requested_quantity" | ||
type="number" | ||
value={field("requested_quantity").value} | ||
onChange={(e) => field("requested_quantity").onChange(e)} | ||
error={state.errors.requested_quantity} | ||
/> | ||
</div> | ||
<div> | ||
<TextFormField | ||
name="assigned_quantity" | ||
type="number" | ||
label="Approved Quantity" | ||
value={field("assigned_quantity").value} | ||
onChange={(e) => field("assigned_quantity").onChange(e)} | ||
disabled={state.form.status !== "PENDING"} | ||
error={state.errors.assigned_quantity} | ||
/> | ||
</div> | ||
|
||
<div className="md:col-span-2"> | ||
<TextAreaFormField | ||
rows={5} | ||
name="reason" | ||
placeholder="Type your description here" | ||
value={state.form.reason} | ||
onChange={handleChange} | ||
label="Description of request*" | ||
error={state.errors.reason} | ||
/> | ||
</div> | ||
<div className="md:col-span-2"> | ||
<TextFormField | ||
name="title" | ||
type="text" | ||
label="Request Title*" | ||
placeholder="Type your title here" | ||
value={field("title").value} | ||
onChange={(e) => field("title").onChange(e)} | ||
error={state.errors.title} | ||
/> | ||
</div> | ||
|
||
<div> | ||
<RadioFormField | ||
name="emergency" | ||
onChange={handleChange} | ||
label={"Is this an emergency?"} | ||
options={[true, false]} | ||
optionLabel={(o) => (o ? "Yes" : "No")} | ||
optionValue={(o) => String(o)} | ||
value={String(state.form.emergency)} | ||
error={state.errors.emergency} | ||
/> | ||
</div> | ||
<div className="md:col-span-2"> | ||
<TextAreaFormField | ||
rows={5} | ||
name="reason" | ||
placeholder="Type your description here" | ||
value={field("reason").value} | ||
onChange={(e) => field("reason").onChange(e)} | ||
label="Description of request*" | ||
error={state.errors.reason} | ||
/> | ||
</div> | ||
|
||
<div className="mt-4 flex flex-col justify-between gap-2 md:col-span-2 md:flex-row"> | ||
<Cancel variant="secondary" onClick={() => goBack()} /> | ||
<Submit onClick={handleSubmit} /> | ||
</div> | ||
</div> | ||
<div> | ||
<RadioFormField | ||
name="emergency" | ||
onChange={(e) => field("emergency").onChange(e)} | ||
label={"Is this an emergency?"} | ||
options={[true, false]} | ||
optionLabel={(o) => (o ? "Yes" : "No")} | ||
optionValue={(o) => String(o)} | ||
value={String(field("emergency").value)} | ||
error={state.errors.emergency} | ||
/> | ||
</div> | ||
</div> | ||
)} | ||
</Form> | ||
</Card> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include 'assigned_facility_type' field in the form
The assigned_facility_type
field is marked as required in your validation logic, but it is not rendered in the form. This will cause the form to fail validation since users have no way to provide this information.
Please add a form field for assigned_facility_type
to allow users to input this required information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rithviknishad Am I supposed to add a field for "assigned_facility_type" as it was not present before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
field("approving_facility_object").onChange({ | ||
name: "approving_facility_object", | ||
value: obj, | ||
}); | ||
field("approving_facility").onChange({ | ||
name: "approving_facility", | ||
value: obj.id, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid using 'any' type for better type safety
The setSelected
function receives obj: any
, which undermines type safety. While previous comments have addressed the use of any
, it's important to define a specific type for obj
to improve maintainability and reduce potential runtime errors.
Consider defining an appropriate type for obj
, such as FacilityModel
or a relevant interface.
errors[field] = requiredFields[field].errorText; | ||
isInvalidForm = true; | ||
validForm = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix logical error in form validation
In the validateForm
function, when a required field is missing, validForm
should be set to false
to indicate that the form is invalid. Currently, it's incorrectly set to true
on line 94.
Apply this diff to correct the logic:
- validForm = true;
+ validForm = false;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
validForm = true; | |
validForm = false; |
if (form.status !== form.initial_status) { | ||
data["status"] = form.status; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add status
field to initForm
The status
field is used in the form but is not initialized in initForm
. This might lead to undefined behavior when accessing form.status
.
Apply this diff to add the status
field:
const initForm: any = {
shifting_approving_facility_object: null,
+ status: "",
assigned_facility_object: null,
emergency: "false",
Committable suggestion skipped: line range outside the PR's diff.
ambulance_driver_name: form.ambulance_driver_name, | ||
ambulance_phone_number: | ||
state.form.ambulance_phone_number === "+91" | ||
form.ambulance_phone_number === "+91" | ||
? "" | ||
: parsePhoneNumber(state.form.ambulance_phone_number), | ||
ambulance_number: state.form.ambulance_number, | ||
: parsePhoneNumber(form.ambulance_phone_number), | ||
ambulance_number: form.ambulance_number, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add breathlessness_level
to initForm
The breathlessness_level
field is used in the form but is not initialized in initForm
. This could cause issues when accessing field("breathlessness_level")
.
Apply this diff to add the breathlessness_level
field:
const initForm: any = {
shifting_approving_facility_object: null,
assigned_facility_object: null,
+ breathlessness_level: "",
emergency: "false",
Committable suggestion skipped: line range outside the PR's diff.
Ensure default value handling for ambulance_phone_number
The logic for setting ambulance_phone_number
might lead to incorrect handling of phone numbers that are exactly "+91". If "+91" is intended as a default or placeholder, consider improving the check to handle empty or invalid phone numbers more robustly.
Apply this diff to improve the validation:
if (form.ambulance_phone_number === "+91" || !form.ambulance_phone_number.trim()) {
""
} else {
parsePhoneNumber(form.ambulance_phone_number)
}
Committable suggestion skipped: line range outside the PR's diff.
<div> | ||
<FieldLabel> | ||
{t("name_of_shifting_approving_facility")} | ||
</FieldLabel> | ||
<FacilitySelect | ||
multiple={false} | ||
name="shifting_approving_facility" | ||
facilityType={1300} | ||
selected={field("shifting_approving_facility").value} | ||
setSelected={(obj: any) => { | ||
field("shifting_approving_facility_object").onChange({ | ||
name: "shifting_approving_facility", | ||
value: obj, | ||
}); | ||
field("approving_facility").onChange({ | ||
name: "approving_facility", | ||
value: obj.id, | ||
}); | ||
}} | ||
errors={field("shifting_approving_facility_object").error} | ||
/> | ||
</div> | ||
)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Field approving_facility
is not defined in initForm
In the setSelected
function for shifting_approving_facility
, the code updates field("approving_facility")
, but approving_facility
is not initialized in initForm
. This may lead to errors when the field is accessed or updated.
Apply this diff to add approving_facility
to initForm
:
const initForm: any = {
shifting_approving_facility_object: null,
+ approving_facility: "",
assigned_facility_object: null,
emergency: "false",
Committable suggestion skipped: line range outside the PR's diff.
👋 Hi, @kihan2518B, This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (9)
src/components/Form/Form.tsx (2)
27-27
: Consider using undefined instead of void in union type.The static analysis tool correctly flags that
void
in a union type can be confusing. Consider usingundefined
for better type safety.- onSubmit: (form: T, source?: string) => Promise<FormErrors<T> | void>; + onSubmit: (form: T, source?: string) => Promise<FormErrors<T> | undefined>;🧰 Tools
🪛 Biome
[error] 27-27: void is confusing inside a union type.
Unsafe fix: Use undefined instead.
(lint/suspicious/noConfusingVoidType)
36-40
: Consider enhancing type safety for additionalButtons.The additionalButtons type is well-structured, but could benefit from using a discriminated union for better type safety.
- additionalButtons?: { - type: "submit" | "button"; - label: string; - id: string; - }[]; + additionalButtons?: Array< + | { type: "submit"; label: string; id: string } + | { type: "button"; label: string; id: string; onClick: () => void } + >;src/components/Facility/StaffCapacity.tsx (4)
37-45
: Add TypeScript types for reducer state and actions.While the reducer implementation is clean, it would benefit from proper TypeScript types for better type safety and maintainability.
-const doctorCapacityReducer = (state = initialState, action: any) => { +interface DoctorCapacityState { + form: typeof initForm; + errors: typeof initForm; +} + +type DoctorCapacityAction = + | { type: 'set_form'; form: typeof initForm } + | { type: 'set_error'; errors: typeof initForm } + | { type: 'set_field'; name: string; value: string; error?: string }; + +const doctorCapacityReducer = ( + state = initialState, + action: DoctorCapacityAction +): DoctorCapacityState => {
87-101
: Enhance count field validation.While the validation logic is good, consider adding additional validation for the count field:
- Ensure it's a valid integer
- Add a reasonable maximum limit
} else if (field === "count" && form[field] < 0) { errors[field] = "Staff count cannot be negative"; validForm = false; +} else if (field === "count") { + const count = Number(form[field]); + if (!Number.isInteger(count)) { + errors[field] = "Staff count must be a whole number"; + validForm = false; + } else if (count > 1000) { // adjust limit as needed + errors[field] = "Staff count exceeds maximum limit"; + validForm = false; + } }
146-148
: Enhance loading state UI.Replace the basic loading text with a proper loading indicator for better user experience.
-<div>Loading...</div> +<div className="flex items-center justify-center p-4"> + <LoadingSpinner /> {/* assuming you have a loading spinner component */} + <span className="ml-2">Loading staff capacity details...</span> +</div>
187-195
: Add HTML5 validation attributes to count field.Enhance the count field with proper HTML5 validation attributes for better user experience and client-side validation.
<TextFormField required id="count" label="Count" name="count" type="number" + min="0" + max="1000" + step="1" value={field("count").value} onChange={(e: any) => field("count").onChange(e)} />src/components/Facility/BedCapacity.tsx (3)
Line range hint
153-204
: Add error handling for API requestsThe submission logic lacks proper error handling for API failures. This could lead to the loading state being stuck if an error occurs.
Add try-catch block and error handling:
const handleSubmit = async (form: typeof initForm, source?: string) => { const valid = validateData(form); if (valid) { setIsLoading(true); + try { const bodyData = { room_type: Number(form.bedType), total_capacity: Number(form.totalCapacity), current_capacity: Number(form.currentOccupancy), }; const { data } = await request( id ? routes.updateCapacity : routes.createCapacity, { pathParams: { facilityId, ...(id ? { bed_id: id.toString() } : {}) }, body: bodyData, }, ); if (data) { // ... existing success handling ... } + } catch (error) { + Notification.Error({ + msg: "Failed to update bed capacity", + }); + } finally { setIsLoading(false); + } } };
268-292
: Enhance form field accessibilityThe number input fields need additional ARIA labels and better validation messaging for screen readers.
Add accessibility improvements:
<TextFormField className="w-full" id="total-capacity" name="totalCapacity" label="Total Capacity" required type="number" + aria-label="Enter total bed capacity" + aria-describedby="total-capacity-hint" value={field("totalCapacity").value} onChange={(e: any) => field("totalCapacity").onChange(e)} error={state.errors.totalCapacity} min={1} /> <TextFormField className="w-full" id="currently-occupied" label="Currently Occupied" required name="currentOccupancy" type="number" + aria-label="Enter current occupancy" + aria-describedby="current-occupancy-hint" value={field("currentOccupancy").value} onChange={(e: any) => field("currentOccupancy").onChange(e)} error={state.errors.currentOccupancy} min={0} max={state.form.totalCapacity} />
146-151
: Optimize last bed type checkThe effect to check for the last bed type could be simplified and made more efficient.
Simplify the logic:
useEffect(() => { - const lastBedType = - bedTypes.filter((i: OptionsType) => i.disabled).length === - BED_TYPES.length - 1; + const disabledCount = bedTypes.reduce((count, type) => + count + (type.disabled ? 1 : 0), 0); + const lastBedType = disabledCount === BED_TYPES.length - 1; setIsLastOptionType(lastBedType); }, [bedTypes]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (5)
cypress.config.ts
(1 hunks)src/components/Facility/BedCapacity.tsx
(5 hunks)src/components/Facility/FacilityBedCapacity.tsx
(1 hunks)src/components/Facility/StaffCapacity.tsx
(3 hunks)src/components/Form/Form.tsx
(8 hunks)
✅ Files skipped from review due to trivial changes (1)
- cypress.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/Facility/FacilityBedCapacity.tsx
🧰 Additional context used
🪛 Biome
src/components/Form/Form.tsx
[error] 27-27: void is confusing inside a union type.
Unsafe fix: Use undefined instead.
(lint/suspicious/noConfusingVoidType)
🔇 Additional comments (6)
src/components/Form/Form.tsx (4)
52-52
: LGTM: Clean implementation of form dirty state.
The isDirty state implementation follows React best practices and is properly initialized.
125-125
: LGTM: Proper state reset on draft restoration.
Correctly resets the dirty state when a draft is restored.
152-168
: LGTM: Clean implementation of dynamic button rendering.
The button rendering implementation is well-structured with:
- Proper key usage in the map
- Consistent disabled state handling
- Clear button identification
66-66
: Verify error handling across all form submissions.
The submit handler implementation looks good, with proper type-safe button identification and error handling. Let's verify the error handling implementation across the codebase.
Also applies to: 80-82
✅ Verification successful
Error handling implementation is consistent across form submissions
The verification of form submissions and error handling patterns across the codebase shows:
- All form submissions properly handle errors through try-catch blocks or response status checks
- Error states are managed consistently using state hooks (setError/setErrors)
- Common error handling patterns found in:
- Form submissions (CreatePrescriptionForm, EditPrescriptionForm)
- Authentication flows (Login, ResetPassword)
- Resource management (ResourceCommentSection, ShiftingCommentsSection)
- Asset management (ConfigureCamera)
The buttonId extraction and error handling in the reviewed code aligns with the codebase's established patterns for form submission handling.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check error handling patterns in form submissions
# Look for consistent error handling patterns in form submission handlers
# Search for onSubmit implementations
rg -A 5 "onSubmit.*=.*async.*=>" --type typescript
# Search for form error handling patterns
rg -A 5 "FormErrors.*void" --type typescript
Length of output: 169
Script:
#!/bin/bash
# Search for form submission handlers and error handling patterns
rg -A 5 "onSubmit.*=.*async.*=>"
rg -A 5 "catch.*Error"
# Look for form-related error state management
rg -A 3 "setError|setFormError"
# Search for form submission implementations
ast-grep --pattern 'const $_ = async ($event: $_) => { $$$ }'
Length of output: 16650
src/components/Facility/StaffCapacity.tsx (1)
10-16
: LGTM! Imports are well-organized.
The new imports for Form components and notifications are appropriate for the component's functionality.
src/components/Facility/BedCapacity.tsx (1)
117-132
:
Fix number conversion logic in validation checks
The number conversion syntax is incorrect in multiple places. The current implementation converts the result of the comparison instead of the form value.
Apply this diff to fix the number conversions:
- } else if (field === "currentOccupancy" && Number(form[field] < 0)) {
+ } else if (field === "currentOccupancy" && Number(form[field]) < 0) {
errors[field] = "Occupied cannot be negative";
validForm = false;
} else if (
field === "currentOccupancy" &&
Number(form[field]) > Number(form.totalCapacity)
) {
errors[field] = "Occupied must be less than or equal to total capacity";
validForm = false;
}
- if (field === "totalCapacity" && Number(form[field]) === 0) {
+ if (field === "totalCapacity" && Number(form[field]) <= 0) {
errors[field] = "Total capacity cannot be 0";
validForm = false;
- } else if (field === "totalCapacity" && Number(form[field] < 0)) {
- errors[field] = "Total capacity cannot be negative";
- validForm = false;
}
Likely invalid or redundant comment.
const handleFieldChange = ( | ||
{ name, value }: FieldChangeEvent<T[keyof T]>, | ||
validate?: FieldValidator<T[keyof T]>, | ||
) => { | ||
dispatch({ | ||
type: "set_field", | ||
name, | ||
value, | ||
error: validate?.(value), | ||
}); | ||
|
||
if (typeof props.defaults[name] == typeof value) { | ||
setIsDirty(props.defaults[name] !== value); | ||
} else { | ||
setIsDirty(JSON.stringify(props.defaults[name]) !== value); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider simplifying the value comparison logic.
The current implementation has separate paths for different types which could be simplified and made more robust.
- if (typeof props.defaults[name] == typeof value) {
- setIsDirty(props.defaults[name] !== value);
- } else {
- setIsDirty(JSON.stringify(props.defaults[name]) !== value);
- }
+ const defaultValue = props.defaults[name];
+ const isEqual = typeof defaultValue === 'object' && defaultValue !== null
+ ? JSON.stringify(defaultValue) === JSON.stringify(value)
+ : defaultValue === value;
+ setIsDirty(!isEqual);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const handleFieldChange = ( | |
{ name, value }: FieldChangeEvent<T[keyof T]>, | |
validate?: FieldValidator<T[keyof T]>, | |
) => { | |
dispatch({ | |
type: "set_field", | |
name, | |
value, | |
error: validate?.(value), | |
}); | |
if (typeof props.defaults[name] == typeof value) { | |
setIsDirty(props.defaults[name] !== value); | |
} else { | |
setIsDirty(JSON.stringify(props.defaults[name]) !== value); | |
} | |
}; | |
const handleFieldChange = ( | |
{ name, value }: FieldChangeEvent<T[keyof T]>, | |
validate?: FieldValidator<T[keyof T]>, | |
) => { | |
dispatch({ | |
type: "set_field", | |
name, | |
value, | |
error: validate?.(value), | |
}); | |
const defaultValue = props.defaults[name]; | |
const isEqual = typeof defaultValue === 'object' && defaultValue !== null | |
? JSON.stringify(defaultValue) === JSON.stringify(value) | |
: defaultValue === value; | |
setIsDirty(!isEqual); | |
}; |
const handleSubmit = async (form: typeof initForm, source?: string) => { | ||
if (!validateData(form)) return; | ||
setIsLoading(true); | ||
const data = { | ||
area: Number(form.area), | ||
count: Number(form.count), | ||
}; | ||
const { res } = await (id | ||
? request(routes.updateDoctor, { | ||
pathParams: { facilityId, id: `${id}` }, | ||
body: data, | ||
}) | ||
: request(routes.createDoctor, { | ||
pathParams: { facilityId }, | ||
body: data, | ||
})); | ||
setIsLoading(false); | ||
if (res?.ok) { | ||
specializationsQuery.refetch(); | ||
Notification.Success({ | ||
msg: id | ||
? "Staff count updated successfully" | ||
: "Staff count added successfully", | ||
}); | ||
handleUpdate(); | ||
|
||
if (submitBtnID === "save-and-exit") handleClose(); | ||
} | ||
if (source !== "save-and-add-more") handleClose(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix loading state management in error scenarios.
The loading state is only reset on successful API response. This could lead to a stuck loading state if the API request fails.
const handleSubmit = async (form: typeof initForm, source?: string) => {
if (!validateData(form)) return;
setIsLoading(true);
const data = {
area: Number(form.area),
count: Number(form.count),
};
- const { res } = await (id
- ? request(routes.updateDoctor, {
- pathParams: { facilityId, id: `${id}` },
- body: data,
- })
- : request(routes.createDoctor, {
- pathParams: { facilityId },
- body: data,
- }));
- setIsLoading(false);
- if (res?.ok) {
- specializationsQuery.refetch();
- Notification.Success({
- msg: id
- ? "Staff count updated successfully"
- : "Staff count added successfully",
- });
- handleUpdate();
+ try {
+ const { res } = await (id
+ ? request(routes.updateDoctor, {
+ pathParams: { facilityId, id: `${id}` },
+ body: data,
+ })
+ : request(routes.createDoctor, {
+ pathParams: { facilityId },
+ body: data,
+ }));
+ if (res?.ok) {
+ specializationsQuery.refetch();
+ Notification.Success({
+ msg: id
+ ? "Staff count updated successfully"
+ : "Staff count added successfully",
+ });
+ handleUpdate();
+ if (source !== "save-and-add-more") handleClose();
+ }
+ } catch (error) {
+ Notification.Error({
+ msg: "Failed to update staff capacity"
+ });
+ } finally {
+ setIsLoading(false);
}
- if (source !== "save-and-add-more") handleClose();
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const handleSubmit = async (form: typeof initForm, source?: string) => { | |
if (!validateData(form)) return; | |
setIsLoading(true); | |
const data = { | |
area: Number(form.area), | |
count: Number(form.count), | |
}; | |
const { res } = await (id | |
? request(routes.updateDoctor, { | |
pathParams: { facilityId, id: `${id}` }, | |
body: data, | |
}) | |
: request(routes.createDoctor, { | |
pathParams: { facilityId }, | |
body: data, | |
})); | |
setIsLoading(false); | |
if (res?.ok) { | |
specializationsQuery.refetch(); | |
Notification.Success({ | |
msg: id | |
? "Staff count updated successfully" | |
: "Staff count added successfully", | |
}); | |
handleUpdate(); | |
if (submitBtnID === "save-and-exit") handleClose(); | |
} | |
if (source !== "save-and-add-more") handleClose(); | |
const handleSubmit = async (form: typeof initForm, source?: string) => { | |
if (!validateData(form)) return; | |
setIsLoading(true); | |
const data = { | |
area: Number(form.area), | |
count: Number(form.count), | |
}; | |
try { | |
const { res } = await (id | |
? request(routes.updateDoctor, { | |
pathParams: { facilityId, id: `${id}` }, | |
body: data, | |
}) | |
: request(routes.createDoctor, { | |
pathParams: { facilityId }, | |
body: data, | |
})); | |
if (res?.ok) { | |
specializationsQuery.refetch(); | |
Notification.Success({ | |
msg: id | |
? "Staff count updated successfully" | |
: "Staff count added successfully", | |
}); | |
handleUpdate(); | |
if (source !== "save-and-add-more") handleClose(); | |
} | |
} catch (error) { | |
Notification.Error({ | |
msg: "Failed to update staff capacity" | |
}); | |
} finally { | |
setIsLoading(false); | |
} | |
}; |
Proposed Changes
when all bed types are added it shows an error message "can't add more bed types" and not allowing user to add more bed types
@ohcnetwork/care-fe-code-reviewers
Merge Checklist
Summary by CodeRabbit
Release Notes
New Features
Form
component to streamline form handling across various components.Improvements
FacilityBedCapacity
component.These changes enhance user experience by providing a more intuitive and efficient interface for managing form data.